<?php
/**
 * ClassLoader.php created on 13 mai 08 
 * Author: Rodrigue Le Gall
 *
 * RPortal is an open source web based Content Management System
 * Copyright (C) 2002-2008  Rodrigue Le Gall
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * @category RPortal2
 * @package  RPortal_Core
 * @author   Rodrigue Le Gall <r.legall@rportal.org>
 * @license  http://www.gnu.org/licenses/gpl-2.0.html GPLv2
 * @link     http://pear.rportal.org/RPortal_Core
 */
 
  declare (ENCODING = 'utf-8');
 
 /**
  * load a class and store it in Injector
  * 
  * @category RPortal2
  * @package  RPortal_Core
  * @author   Rodrigue Le Gall <r.legall@rportal.org>
  * @license  http://www.gnu.org/licenses/gpl-2.0.html GPLv2
  * @link     http://pear.rportal.org/RPortal_Core
  */
class ClassLoader
{
    public static $path = array ();
    public static $loading = array ();
    
    /**
     * Load a file and the contained class
     * 
     * @param strinf $filePath the real path of the file
     * 
     * @return void
     */
    public static function loadFile($filePath)
    {
        if (!is_file($filePath)) {
            throw new RPFileNotFoundException($filePath);
        }
        $filePath = realpath($filePath);
        if (pathinfo($filePath, PATHINFO_EXTENSION)==='php') {
            $fileName = basename($filePath, '.php');
            include_once $filePath;
            if (class_exists($fileName, false) || interface_exists($fileName, false)) {
                $rClass = new ReflectionClass($fileName);
                if ($rClass->getFileName() === $filePath) {
                    // Use reflexion to find implemented interface
                    if (!$rClass->isInterface()) {
                        Injector :: addClass($fileName, $filePath);
                        // Add each implemented interface as an injection
                        $interfaces =  $rClass->getInterfaces();
                        while (list($key, $interface) = each($interfaces)) {
                            Injector :: addInjection($interface->getName(), $fileName);
                        }
                    } else {
                        Injector :: addInterface($fileName, $filePath);
                    }
                }
            }
        }
    }

    /**
     * load the class contained in the folder's files
     * 
     * @param string $folderPath the real path of the folder
     * 
     * @return void
     */
    public static function loadFolder($folderPath)
    {
        $d = dir($folderPath);
        while (false !== ($entry = $d->read())) {
            if ($entry!='.' && $entry!='..') {
                $currentPath = $folderPath.'/'.$entry;
                if (is_dir($currentPath)) {
                    ClassLoader :: loadFolder($currentPath);
                } else {
                    if (pathinfo($currentPath, PATHINFO_EXTENSION)==='php') {
                        $fileName = basename($currentPath, '.php');
                        ClassLoader :: $loading[$fileName] = $currentPath;
                    }
                }
            }
        }
        $d->close();
        while (list($key, $value) = each(ClassLoader :: $loading)) {
            ClassLoader :: loadFile($value);
        }
        ClassLoader :: $loading = array();
    }
}

/**
 * This is a magic function of php to load automatically class definition
 * 
 * @param string $class_name the name of the researched class
 * 
 * @return void
 */
function __autoload($class_name)
{
    if (!isset (ClassLoader :: $path[$class_name])) {
        try {
            $file = Injector::getFile($class_name);
            ClassLoader :: $path[$class_name] = $file;
            include_once ClassLoader :: $path[$class_name];
        } catch(RPUndefinedClassException $e){
            if (isset(ClassLoader :: $loading[$class_name])) {
                // look for a loading class ???
                ClassLoader :: LoadFile(ClassLoader :: $loading[$class_name]);
                ClassLoader :: $path[$class_name] = ClassLoader :: $loading[$class_name];
            }
        }
    } else {
        include_once ClassLoader :: $path[$class_name];
    }
}